package chagine.core.log;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.util.StringUtils;

import java.util.HashMap;

/**
 * LoggingApplicationListener
 * Created by 王彬安（wba）on 2017/8/7.
 */
public class LoggingApplicationListener implements GenericApplicationListener {

    /**
     * 它的优先级要求比 spring 的 logging 监听器要高，才能事先设置一些参数
     */
//    public static final int ORDER = org.springframework.boot.logging.LoggingApplicationListener.DEFAULT_ORDER - 1;
    public static final int ORDER = org.springframework.boot.context.logging.LoggingApplicationListener.DEFAULT_ORDER - 1;

    private static Class<?>[] EVENT_TYPES = {ApplicationEnvironmentPreparedEvent.class};

    private static Class<?>[] SOURCE_TYPES = {SpringApplication.class,
            ApplicationContext.class};

    @Override
    public boolean supportsEventType(ResolvableType resolvableType) {
        return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return isAssignableFrom(sourceType, SOURCE_TYPES);
    }

    private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
        if (type != null) {
            for (Class<?> supportedType : supportedTypes) {
                if (supportedType.isAssignableFrom(type)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            ConfigurableEnvironment environment = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment();
            String loggingConfig = environment.getProperty("logging.config");
            if (StringUtils.isEmpty(loggingConfig)) {
                // 用户没有指定日志的配置文件
                String loggingFile = environment.getProperty("logging.file");
                if (StringUtils.isEmpty(loggingFile)) {
                    // 没有日志文件，那么输出到终端上
                    loggingConfig = "classpath:META-INF/logback-console-spring.xml";
                } else {
                    loggingConfig = "classpath:META-INF/logback-chagine-spring.xml";
                }
                setLoggingConfig(environment, loggingConfig);
            }
        }
    }

    /**
     * 把配置写到环境中
     *
     * @param environment
     * @param loggingConfig
     */
    private void setLoggingConfig(ConfigurableEnvironment environment, String loggingConfig) {
        if (environment != null) {
            MapPropertySource seeingLogging = new MapPropertySource("SeeingLogging",
                    new HashMap<String, Object>(1) {
                        {
                            put("logging.config", loggingConfig);
                        }
                    });
            environment.getPropertySources().addLast(seeingLogging);
        } else {
            System.setProperty("logging.config", loggingConfig);
        }
    }

    /**
     * 它的优先级要求比 spring 的 logging 监听器要高，才能事先设置一些参数
     *
     * @return
     */
    @Override
    public int getOrder() {
        return ORDER;
    }
}
